package com.xu.ai.model.dashscope.controller;

import java.util.List;
import java.util.Map;

import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatOptions;
import com.alibaba.cloud.ai.dashscope.spec.DashScopeModel;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor;
import org.springframework.ai.chat.client.advisor.vectorstore.QuestionAnswerAdvisor;
import org.springframework.ai.chat.memory.ChatMemory;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.UserMessage;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.ai.chat.prompt.PromptTemplate;
import org.springframework.ai.chat.prompt.SystemPromptTemplate;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.rag.advisor.RetrievalAugmentationAdvisor;
import org.springframework.ai.rag.retrieval.search.VectorStoreDocumentRetriever;
import org.springframework.ai.vectorstore.SimpleVectorStore;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;

import com.xu.ai.model.dashscope.advisor.ReasoningContentAdvisor;
import com.xu.ai.model.dashscope.pojo.Poetry;
import com.xu.ai.model.dashscope.prompt.SystemPrompt;
import com.xu.ai.model.dashscope.tools.DateTimeTool;
import com.xu.ai.model.dashscope.tools.ITool;

/**
 * 聊天客户端ChatClient controller
 *
 * @author xuguan
 * @since 2025/9/15
 */
@RestController
@RequestMapping("/api/chat")
public class ChatClientController {

	private final ChatClient chatClient;

	private final ChatMemory chatMemory;

	private final VectorStore vectorStore;

	private final ITool dateTimeTool;

	public ChatClientController(EmbeddingModel embeddingModel,
								ChatClient.Builder chatClientBuilder,
								ChatMemory chatMemory) {
		this.chatClient = chatClientBuilder.defaultSystem(SystemPrompt.DEFAULT_CHAT_SYSTEM.getTemplate())
				.defaultAdvisors(SimpleLoggerAdvisor.builder().build())
				.build();
		this.chatMemory = chatMemory;
		this.vectorStore = SimpleVectorStore.builder(embeddingModel).build();
		this.dateTimeTool = new DateTimeTool();
	}

	@GetMapping(path = "/call-content")
	public String callContent(@RequestParam(value = "userInput", defaultValue = "你是谁?") String userInput) {
		return this.chatClient.prompt().user(userInput).call().content();
	}

	@GetMapping(path = "/call-entity-poetry")
	public Poetry callEntityPoetry(@RequestParam(value = "author", defaultValue = "李白") String author) {
		final PromptTemplate pt = PromptTemplate.builder()
				.template("""
						你是一个博学多才的文学大师, 你精通中华古诗词.
												
						你需要根据用户输入的诗人名称, 输出这个诗人最有名的古诗词,
						标题使用《》包括起来, 例如: 《梦游天姥吟留别》
						按照作者, 标题, 内容的结构体输出.
												
						诗人名称: {author}
						""")
				.build();
		final Prompt prompt = pt.create(Map.of("author", author), DashScopeChatOptions.builder().withIncrementalOutput(false).build());
		return this.chatClient.prompt(prompt).call().entity(Poetry.class);
	}

	@GetMapping(path = "/stream-content", produces = "text/html;charset=UTF-8")
	public Flux<String> streamContent(@RequestParam(value = "userInput", defaultValue = "你是谁?") String userInput) {
		return this.chatClient.prompt().user(userInput).stream().content();
	}

	@GetMapping(path = "/stream-chat-response")
	public Flux<ChatResponse> streamChatResponse(@RequestParam(value = "userInput", defaultValue = "你是谁?") String userInput) {
		return this.chatClient.prompt().user(userInput).stream().chatResponse();
	}

	@GetMapping(path = "/choose-model-chat", produces = "text/html;charset=UTF-8")
	public Flux<String> chooseModelChat(@RequestParam(value = "userInput", defaultValue = "你是谁?") String userInput,
										@RequestParam(value = "model", defaultValue = "qwen-plus") String model) {
		return this.chatClient.prompt()
				.user(userInput)
				.options(DashScopeChatOptions.builder().model(model).build())
				.stream()
				.content();
	}

	@GetMapping(path = "/deep-thinking", produces = "text/html;charset=utf-8")
	public Flux<String> deepThinking() {
		return this.chatClient.prompt()
				.options(DashScopeChatOptions.builder()
						.model(DashScopeModel.ChatModel.QWEN_PLUS.getName())
						.withEnableThinking(Boolean.TRUE)
						.withStream(Boolean.TRUE)
						.build())
				.advisors(new ReasoningContentAdvisor())
				.user("给我讲一个生动的故事, 结合安徒生童话, 请思考后再回答")
				.stream()
				.content();
	}

	@GetMapping(path = "/choose-model-thinking", produces = "text/html;charset=UTF-8")
	public Flux<String> chooseModelThinking(@RequestParam(value = "userInput", defaultValue = "你是谁?") String userInput,
											@RequestParam(value = "model", defaultValue = "qwen-plus") String model) {
		return this.chatClient.prompt()
				.options(DashScopeChatOptions.builder().model(model).withEnableThinking(true).build())
				.user(userInput)
				.stream()
				.content();
	}

	@GetMapping(path = "/web-search", produces = "text/html;charset=utf-8")
	public Flux<String> webSearch() {
		return this.chatClient.prompt()
				.options(DashScopeChatOptions.builder()
						.model(DashScopeModel.ChatModel.QWEN_PLUS.getName())
						.withEnableSearch(Boolean.TRUE)
						.withStream(Boolean.TRUE)
						.build())
				.user("查询一下杭州今天的天气")
				.stream()
				.content();
	}

	@GetMapping(path = "/prompt", produces = "text/html;charset=UTF-8")
	public Flux<String> prompt(@RequestParam(value = "name", defaultValue = "xu-ai智能助手") String name,
							   @RequestParam(value = "voice", defaultValue = "幽默") String voice) {
		String userText = """
				告诉我海盗黄金时代的三位著名海盗以及他们这样做的原因。
				至少为每个海盗写一句话。
				""";
		Message userMessage = UserMessage.builder().text(userText).build();

		String systemText = """
				您是一个有用的人工智能助手，可以帮助人们查找信息。
				你的名字是 {name},
				您应该使用你的姓名并以 {voice} 的风格回复用户的请求。
				""";
		SystemPromptTemplate systemPromptTemplate = SystemPromptTemplate.builder().template(systemText).build();
		Message systemMessage = systemPromptTemplate.createMessage(Map.of("name", name, "voice", voice));

		Prompt prompt = Prompt.builder().messages((List.of(userMessage, systemMessage))).build();

		return this.chatClient.prompt(prompt).user(userText).stream().content();
	}

	@GetMapping(path = "/chat-memory", produces = "text/html;charset=UTF-8")
	public Flux<String> chatMemory(@RequestParam(value = "userInput", defaultValue = "你是谁?") String userInput,
								   @RequestParam(value = "chatId", defaultValue = ChatMemory.DEFAULT_CONVERSATION_ID) String chatId) {
		return this.chatClient.prompt()
				.user(userInput)
				.advisors(MessageChatMemoryAdvisor.builder(chatMemory).build())
				.advisors(a -> a.param(ChatMemory.CONVERSATION_ID, chatId))
				.stream()
				.content();
	}

	@GetMapping(path = "/query-answer-rag", produces = "text/html;charset=UTF-8")
	public Flux<String> queryAnswerRag(@RequestParam(value = "userInput", defaultValue = "你是谁?") String userInput) {
		return this.chatClient.prompt()
				.user(userInput)
				.advisors(QuestionAnswerAdvisor.builder(vectorStore).build())
				.stream()
				.content();
	}

	@GetMapping(path = "/document-retriever-rag", produces = "text/html;charset=UTF-8")
	public Flux<String> documentRetrieverRag(
			@RequestParam(value = "userInput", defaultValue = "你是谁?") String userInput) {
		return this.chatClient.prompt()
				.user(userInput)
				.advisors(RetrievalAugmentationAdvisor.builder()
						.documentRetriever(VectorStoreDocumentRetriever.builder()
								.vectorStore(vectorStore)
								.similarityThreshold(0.5d)
								.topK(3)
								.build())
						.build())
				.stream()
				.content();
	}

	@GetMapping(path = "/chat-memory-rag", produces = "text/html;charset=UTF-8")
	public Flux<String> chatMemoryRag(@RequestParam(value = "userInput", defaultValue = "你是谁?") String userInput,
									  @RequestParam(value = "chatId", defaultValue = ChatMemory.DEFAULT_CONVERSATION_ID) String chatId) {
		return this.chatClient.prompt()
				.user(userInput)
				.advisors(MessageChatMemoryAdvisor.builder(chatMemory).build())
				.advisors(a -> a.param(ChatMemory.CONVERSATION_ID, chatId))
				.advisors(RetrievalAugmentationAdvisor.builder()
						.documentRetriever(VectorStoreDocumentRetriever.builder()
								.vectorStore(vectorStore)
								.similarityThreshold(0.5d)
								.topK(3)
								.build())
						.build())
				.stream()
				.content();
	}

	@GetMapping(path = "/tool", produces = "text/html;charset=UTF-8")
	public Flux<String> tool(@RequestParam(value = "userInput", defaultValue = "当前时间是多少") String userInput) {
		return this.chatClient.prompt().user(userInput).tools(dateTimeTool).stream().content();
	}

}
